﻿using System;
using System.Linq;
using System.Threading;
using MDK.Common;
using MDK.Device.Components;
using MDK.Device.Devices;
using MDK.Model.Models;

namespace MDK.Device
{
    public class SystemModel
    {
        public Atm Atm { get; set; }
        public Freezer Freezer { get; set; }
        public FrontDevice Front { get; set; }
        public BackDevice Back { get; set; }
        public Back2Device Back2 { get; set; }
        public Centrifuge[] Centrifuges { get; set; }

        private static SystemModel _instance;
        
        public static SystemModel Instance
        {
            get { return _instance ?? (_instance = new SystemModel()); }
        }

        private SystemModel()
        {
            var plc1 = new PlcDevice(new MitsubishiPlc("192.168.2.101", 4999));
            var plc2 = new PlcDevice(new MitsubishiPlc("192.168.2.102", 4998));
            var plc3 = new PlcDevice(new MitsubishiPlc("192.168.2.103", 5000));
            var plc4 = new PlcDevice(new MitsubishiPlc("192.168.2.104", 5000));
            Front = new FrontDevice(plc1);
            Atm = new Atm(plc2);
            Freezer = new Freezer(plc2);
            Back = new BackDevice(plc3);
            Back2 = new Back2Device(plc4);
            Centrifuges = new Centrifuge[2];
            Centrifuges[0] = new Centrifuge("192.168.2.201");
            Centrifuges[1] = new Centrifuge("192.168.2.202");
            Centrifuges[0].TurnOnCompressor();
            Centrifuges[1].TurnOnCompressor();
        }

        public int AllocCentrifuge()
        {
            Centrifuges[0].IsEnable = IDatatoFlow.IsCentrifugeEnable("LeftCentrifuge");
            Centrifuges[1].IsEnable = IDatatoFlow.IsCentrifugeEnable("RightCentrifuge");
            return Centrifuges[0].UseCount <= Centrifuges[1].UseCount ? (Centrifuges[0].IsFree&& Centrifuges[0].IsEnable ? 0 : (Centrifuges[1].IsFree&& Centrifuges[1].IsEnable ? 1 : -1)) : (Centrifuges[1].IsFree&& Centrifuges[1].IsEnable ? 1 : (Centrifuges[0].IsFree && Centrifuges[0].IsEnable ? 0 : -1));
        }

        public void FrontDragPallet(Position from, Position to, Action doBeforeDrag = null, Action doAfterDrag = null, Action doAfterDrop = null,bool IsEarlierY=false)
        {
            // 开手指
            Front.Finger.TurnOn();
            // 提臂
            Front.Z.Goto(0);
            Front.SZ.Goto(0);
            Front.Z.WaitCompleted();
            Front.SZ.WaitCompleted();
            // 去源位置
            Front.X.Goto(from.X);
            Front.Y.Goto(from.Y);
            Front.X.WaitCompleted();
            Front.Y.WaitCompleted();

            doBeforeDrag?.Invoke();

            // 抓
            Front.Z.Goto(from.Z);
            Front.SZ.Goto(from.SZ);
            Front.Z.WaitCompleted();
            Front.SZ.WaitCompleted();
            // 夹
            Front.Finger.TurnOff();

            doAfterDrop?.Invoke();
            // 提托
            Front.Z.Goto(0);
            Front.SZ.Goto(0);
            Front.Z.WaitCompleted();
            Front.SZ.WaitCompleted();
            // 去目标
            if ((from.Id == "60001" && to.X < from.X) || (from.Id == "60002" && to.X > from.X))
            {
                Front.Y.Goto(to.Y);
                while (Front.Y.CurrentCoord < 210)
                {
                    Thread.Sleep(10);
                }
                Front.X.Goto(to.X);     
                Front.X.WaitCompleted();
                Front.Y.WaitCompleted();
                doAfterDrag?.Invoke();
            }
            else
            {
                if (IsEarlierY)
                {
                    Front.Y.Goto(to.Y);
                    Front.Y.WaitCompleted();
                    Front.X.Goto(to.X);
                    Front.X.WaitCompleted();
                    doAfterDrag?.Invoke();

                }
                else
                {
                    Front.X.Goto(to.X);
                    Front.Y.Goto(to.Y);
                    Front.X.WaitCompleted();
                    Front.Y.WaitCompleted();
                    doAfterDrag?.Invoke();
                }
               
            }
            
            // 放
            Front.Z.Goto(to.Z);
            Front.SZ.Goto(to.SZ);
            Front.Z.WaitCompleted();
            Front.SZ.WaitCompleted();
            // 松
            Front.Finger.TurnOn();
            // 提臂
            Front.Z.Goto(0);
            Front.SZ.Goto(0);

            Front.Z.WaitCompleted();
            Front.SZ.WaitCompleted();

            to.Pallet = from.Pallet;
            from.Pallet = null;

            for (int i = 0; i < to.Pallet.Tubes.Length; i++)
            {
                var tube = to.Pallet.Tubes[i];
                if (tube.Type == TubeTypes.None) continue;
                IDatatoFlow.SampleUpdate(new T_Sample
                {
                    Id = tube.Id,
                    PostionId = to.Id,
                    Is_Delete = false,
                    Index = i,
                    State = 1,
                    ReBarCode = to.Pallet.ActiveBarcode
                });
            }
        }

        public void ScanFrontDragTube(Position position, int hole, Action doAfterDrag = null, Action doAfterDrop = null)
        {
            Front.X.Goto(position.GetHoleX(hole));
            Front.Y.Goto(position.GetHoleY(hole));
            Front.X.WaitCompleted();
            Front.Y.WaitCompleted();

            Front.Z.Goto(position.Z);
            Front.SZ.Goto(position.TubeSZ);
            Front.Z.WaitCompleted();
            Front.SZ.WaitCompleted();

            if (Front.FingerCheckSensor.IsActive())
            {
                position.Pallet.Tubes[hole].Type = TubeTypes.Meimian;

                Front.Z.Goto(position.Z);
                Front.SZ.Goto(position.TubeSZ);
                Front.Z.WaitCompleted();
                Front.SZ.WaitCompleted();

                Front.Finger.TurnOff();

                Front.Z.Goto(0);
                Front.SZ.Goto(0);
                Front.Z.WaitCompleted();
                Front.SZ.WaitCompleted();

                doAfterDrag?.Invoke();

                Front.Z.Goto(position.Z);
                Front.SZ.Goto(position.TubeSZ);
                Front.Z.WaitCompleted();
                Front.SZ.WaitCompleted();

                Front.Finger.TurnOn();
            }

            Front.Z.Goto(0);
            Front.SZ.Goto(0);

            doAfterDrop?.Invoke();

            Front.Z.WaitCompleted();
            Front.SZ.WaitCompleted();
        }

        public void FrontDragTube(Position from, int fromHole, Position to, int toHole, Action doAfterDrag = null, Action doAfterDrop = null)
        {
            Front.Finger.TurnOn();
            Front.Z.Goto(0);
            Front.SZ.Goto(0);
            Front.Z.WaitCompleted();
            Front.SZ.WaitCompleted();

            Front.X.Goto(from.GetHoleX(fromHole));
            Front.Y.Goto(from.GetHoleY(fromHole));
            Front.X.WaitCompleted();
            Front.Y.WaitCompleted();

            Front.Z.Goto(from.Z);
            Front.SZ.Goto(from.TubeSZ);
            Front.Z.WaitCompleted();
            Front.SZ.WaitCompleted();

            Front.Finger.TurnOff();

            Front.Z.Goto(0);
            Front.SZ.Goto(0);
            Front.Z.WaitCompleted();
            Front.SZ.WaitCompleted();

            Front.X.Goto(to.GetHoleX(toHole));
            Front.Y.Goto(to.GetHoleY(toHole));

            doAfterDrag?.Invoke();

            Front.X.WaitCompleted();
            Front.Y.WaitCompleted();

            Front.Z.Goto(to.Z);
            Front.SZ.Goto(to.TubeSZ);
            Front.Z.WaitCompleted();
            Front.SZ.WaitCompleted();

            Front.Finger.TurnOn();

            Front.Z.Goto(0);
            Front.SZ.Goto(0);

            doAfterDrop?.Invoke();

            Front.Z.WaitCompleted();
            Front.SZ.WaitCompleted();

            if (to != from || toHole != fromHole)
            {
                to.Pallet.Tubes[toHole] = from.Pallet.Tubes[fromHole];
                from.Pallet.Tubes[fromHole] = new Tube();

                var tube = to.Pallet.Tubes[toHole];
                IDatatoFlow.SampleUpdate(new T_Sample
                {
                    Id = tube.Id,
                    PostionId = to.Id,
                    Is_Delete = false,
                    Index = toHole,
                    State = 1,
                    ReBarCode = to.Pallet.ActiveBarcode
                });
            }
        }

       

        public void BackDragTube(Position from, int fromHole, Position to, int toHole, Action doAfterDrag = null)
        {
            Back.Finger.TurnOn();
            Back.SZ.Goto(0);
            Back.FingerRotator.Rotate(-25, RotateRefLocations.Zero);
            Back.SZ.WaitCompleted();
            Back.Y.Goto(from.GetHoleY(fromHole));
            Back.X.Goto(from.GetHoleX(fromHole));
            Back.Y.WaitCompleted();
            Back.X.WaitCompleted();
            Back.FingerRotator.WaitCompleted();
            Back.SZ.Goto(from.TubeSZ);
            Back.Finger.TurnOff();
            Back.SZ.Goto(0);

            if (from.Type == PositionTypes.Belt)
            {
                Back.FingerRotator.Rotate(-120, RotateRefLocations.Barcode);
            }

            Back.SZ.WaitCompleted();

            doAfterDrag?.Invoke();

            if (from.Type == PositionTypes.Belt && (fromHole == 1 || fromHole == 5))
            {
                Back.Y.Goto(from.Y + 21);
                Back.Y.WaitCompleted();
            }
            Back.X.Goto(to.GetHoleX(toHole));
            while ((from.Type == PositionTypes.Belt && Back.X.CurrentCoord < from.X + 21) || (from.Type == PositionTypes.Dial && Back.X.CurrentCoord < from.X + 50))
            {
                Thread.Sleep(10);
            }
            Back.Y.Goto(to.GetHoleY(toHole));

            Back.X.WaitCompleted();
            Back.Y.WaitCompleted();
            if (from.Type == PositionTypes.Belt)
            {
                Back.FingerRotator.WaitCompleted();
            }

            Back.SZ.Goto(to.TubeSZ);
            Back.SZ.WaitCompleted();

            Back.Finger.TurnOn();
            Back.SZ.Goto(0);
            Back.SZ.WaitCompleted();
        }

       

        public void BackCollectPallet(Position from, Position to)
        {
            Back.Finger.TurnOn();
            Back.SZ.Goto(0);
            Back.SZ.WaitCompleted();

            Back.Y.Goto(from.Y);
            Back.X.Goto(from.X);
            Back.Y.WaitCompleted();
            Back.X.WaitCompleted();
            Back.SZ.Goto(from.SZ);
            Back.SZ.WaitCompleted();

            Back.Finger.TurnOff();

            Back.Belt.Stop();

            Back.SZ.Goto(0);
            Back.SZ.WaitCompleted();
            Back.Y.Goto(to.Y);
            Back.X.Goto(to.X);
            Back.Y.WaitCompleted();
            Back.X.WaitCompleted();
            Back.SZ.Goto(to.SZ);
            Back.SZ.WaitCompleted();
            Back.Finger.TurnOn();

            Back.SZ.Goto(0);
            Back.SZ.WaitCompleted();
        }
    }
}